package com.resifind.www.util;

import com.resifind.www.config.JdbcConfig;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 36069
 */
public class JdbcUtils {

    /**
     * 获取连接
     *
     * @return 数据库连接对象
     */
    public static Connection getConn() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            return DriverManager.getConnection(JdbcConfig.DB_URL, JdbcConfig.DB_USER, JdbcConfig.DB_PASS);
        } catch (ClassNotFoundException | SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 关闭连接
     *
     * @param conn 数据库连接对象
     * @param pst  预编译语句对象
     * @param rs   结果集对象
     */
    public static void closeConn(Connection conn, PreparedStatement pst, ResultSet rs) {
        try {
            if (conn != null) {
                conn.close();
            }
            if (pst != null) {
                pst.close();
            }
            if (rs != null) {
                rs.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 开启事务
     *
     * @param conn 数据库连接对象
     */
    public static void beginTransaction(Connection conn) {
        try {
            if (conn != null) {
                conn.setAutoCommit(false);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 提交事务
     *
     * @param conn 数据库连接对象
     */
    public static void commitTransaction(Connection conn) {
        try {
            if (conn != null) {
                conn.commit();
                conn.setAutoCommit(true);
            }
        } catch (SQLException e) {
            rollbackTransaction(conn);
            throw new RuntimeException(e);
        }
    }

    /**
     * 回滚事务
     *
     * @param conn 数据库连接对象
     */
    public static void rollbackTransaction(Connection conn) {
        try {
            if (conn != null) {
                conn.rollback();
                conn.setAutoCommit(true);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通用查询方法
     *
     * @param sql    查询语句
     * @param params 查询参数数组
     * @param mapper 结果集映射器
     * @return 查询结果列表
     */
    public static <T> List<T> query(String sql, Object[] params, ResultSetMapper<T> mapper) {
        Connection conn = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        try {
            conn = getConn();
            //noinspection SqlSourceToSinkFlow
            pst = conn.prepareStatement(sql);
            //设置参数
            setParams(params, pst);
            rs = pst.executeQuery();
            List<T> list = new ArrayList<>();
            while (rs.next()) {
                //调用mapper的map方法，将结果集映射为对象
                list.add(mapper.map(rs));
            }
            return list;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            closeConn(conn, pst, rs);
        }
    }

    /**
     * 通用增删改方法
     *
     * @param sql    增删改语句
     * @param params 查询参数数组
     * @return 受影响的行数
     */
    public static boolean update(String sql, Object[] params, Connection conn) {
        PreparedStatement pst = null;
        try {
            //noinspection SqlSourceToSinkFlow
            pst = conn.prepareStatement(sql);
            //设置参数
            setParams(params, pst);
            return pst.executeUpdate() > 0;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            closeConn(null, pst, null);
        }
    }

    /**
     * 设置参数
     *
     * @param params 参数数组
     * @param pst    预编译语句对象
     * @throws SQLException 数据库异常
     */
    private static void setParams(Object[] params, PreparedStatement pst) throws SQLException {
        if (params != null) {
            for (int i = 0; i < params.length; i++) {
                pst.setObject(i + 1, params[i]);
            }
        }
    }
}
